package demo.aspect;

import framework.aop.aspect.InchJoinPoint;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;

/**
 * Aspect class to cut in before/after/afterReturning/afterThrowing
 * around is not implemented
 */
@Slf4j
public class logAspect {
    /**
     * method that execute before the point cut
     * @param joinPoint the point cut , eg: demo.services.impl.QueryService.query()
     */
    public void before(InchJoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        //record the start time
        joinPoint.setUserAttribute("startTime_" + joinPoint.getMethod().getName(),
                startTime);
        //log out info
        log.info("\nInvoker Before Method."
                + "\nTargetObject:\t" + joinPoint.getMethod()
                + "\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                + "\nStartTime:\t" + startTime);
    }
    /**
     * method that execute after the point cut
     * @param joinPoint the point cut , eg: demo.services.impl.QueryService.query()
     */
    public void after(InchJoinPoint joinPoint) {
        //get the start time
        Object objtime = joinPoint.getUserAttribute("startTime_" + joinPoint.getMethod().getName());
        //log out info
        //check if the start time is not recorded
        if (objtime != null) {
            long startTime = (long) objtime;
            long endTime = System.currentTimeMillis();
            log.info("\nInvoker After Method."
                    +"\nTargetObject:\t"+joinPoint.getMethod()
                    +"\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                    +"\nStartTime:\t" + startTime
                    +"\nEndTime:\t" + endTime
                    +"\nTime used:\t" + (endTime-startTime));
        } else {
            long endTime = System.currentTimeMillis();
            log.info("\nInvoker After Method."
                    +"\nTargetObject:\t"+joinPoint.getMethod()
                    +"\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                    +"\nEndTime:\t" + endTime);
        }
    }
    /**
     * method that execute after the point cut returns
     * @param joinPoint the point cut , eg: demo.services.impl.QueryService.query()
     */
    public void afterReturning(InchJoinPoint joinPoint,Object result){
        //get the start time
        Object objtime = joinPoint.getUserAttribute("startTime_" + joinPoint.getMethod().getName());
        //log out info
        //check if the start time is not recorded
        if (objtime != null) {
            long startTime = (long) objtime;
            long endTime = System.currentTimeMillis();
            log.info("\nInvoker After returning."
                    +"\nTargetObject:\t"+joinPoint.getMethod()
                    +"\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                    +"\nResult:\t" + result.toString()
                    +"\nStartTime:\t" + startTime
                    +"\nEndTime:\t" + endTime
                    +"\nTime used:\t" + (endTime-startTime));
        } else {
            long endTime = System.currentTimeMillis();
            log.info("\nInvoker After returning."
                    +"\nTargetObject:\t"+joinPoint.getMethod()
                    +"\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                    +"\nResult:\t" + result.toString()
                    +"\nEndTime:\t" + endTime);
        }
    }
    /**
     * method that execute after the point cut throws an exception
     * @param joinPoint the point cut , eg: demo.services.impl.ModifyService.remove()
     */
    public void afterThrowing(InchJoinPoint joinPoint,Throwable throwable) {
        //log out info
        log.info("\nException found."
                +"\nTargetObject:\t"+joinPoint.getMethod()
                +"\nArgs:\t" + Arrays.toString(joinPoint.getArguments())
                +"\nThrows:\t" + throwable.getMessage());
    }
}
